//Queue implementation using an array, full condition is f==r, empty is f = r-1
//Q can hold arraysize-1 elements only
//rear sees inserts and front sees removal


#include "stdio.h"
#include "stdlib.h"

//For rand()
#include <time.h>


typedef int elementType;

struct queueType
{
	elementType *elemArray;
	int size, front, rear, capacity;
};

typedef struct queueType *queue;

queue createQueue(int size);
void disposeQueue(queue *pq);
int isEmpty(queue q);
void makeEmpty(queue q);
int enqueue(queue q, elementType x);
elementType dequeue(queue q);
elementType front(queue q);



queue createQueue(int  size)
{

	queue q = (queue)malloc(sizeof(struct queueType));
	if(q && size>0){  //can hold 1 or more elements
		q->capacity = size;
		q->size = 0; //current size
		q->elemArray = (elementType*)malloc(sizeof(elementType) * size);
		if(q->elemArray){
			q->front = 0;
			q->rear = 0;
			return q;
		}

		free(q);
	}
		
		
	return NULL;
}


//Must modify calling function's queueType address holder(ptr)
void disposeQueue(queue *pq)
{
	if( pq && (*pq) && (*pq)->elemArray){
		free((*pq)->elemArray); //free the queue element array pointed to by the queueType struct at pq
		free((*pq)); //free the queueType struct
		*pq = NULL; //set the queueType struct ptr to NULL in the calling function(using address of the ptr i.e. a ptr to ptr to queueType struct)
	}
}


int isEmpty(queue q)
{
	
	if(q && q->size == 0)
		return 1;
	
	return 0;
}


void makeEmpty(queue q)
{
	if(q){	
		q->front = 0;
		q->rear = 0;
		q->size = 0;
	}	
}


int enqueue(queue q, elementType x)
{
	if(q && q->size < q->capacity){	//size is kept in sync
		q->elemArray[q->rear] = x;
		q->rear = (q->rear + 1)%(q->capacity);
		q->size++;
		return 1;
	}	

	return 0;
}


//What about empty queue, how to signal it ?
elementType dequeue(queue q)
{
	elementType x;

	if(q && !isEmpty(q)){	
		printf("%d\n", q->front);
		x = q->elemArray[q->front];
		q->front = (q->front + 1)%(q->capacity);		
		q->size--;
		return x;
	}	

	return 0;
}


elementType front(queue q)
{
	if(q && !isEmpty(q))
		return q->elemArray[q->front];

	return 0;
}

void printQueue(queue q)
{
	int i;
	for(i=0; i<q->capacity; i++){
		printf("Q[%2d] = %d", i, q->elemArray[i]);

		if(i == q->front)
			printf("<-f\n");
		else if(i == q->rear)
			printf("<-r\n");
		else
			printf("\n");
	}
}


void printQueueFile(queue q, FILE* f)
{
	int i;
	for(i=0; i<q->capacity; i++){
		fprintf(f, "Q[%2d] = %d", i, q->elemArray[i]);

		if(i == q->front)
			fprintf(f, "<-f\n");
		else if(i == q->rear)
			fprintf(f, "<-r\n");
		else
			fprintf(f, "\n");
	}
}

int main(int argc, char* argv[])
{
	queue q = createQueue(10);
	int i, r;

	unsigned int iseed = (unsigned int)time(NULL);
	srand(iseed);

	FILE *f = fopen("Log.txt", "w");

	for(i=0; i<200; i++){

		r = 1 + (int)( 10.0 * rand()/( RAND_MAX + 1.0 ) );

		if(r%2==0){
			fprintf(f, "Enqueue %d\n", r);
			enqueue(q, r);
		}
		else if(r%3==0){
			makeEmpty(q);
			fprintf(f, "MakeEmpty: %d\n", r);			
		}
		else if(r%5==0){
			disposeQueue(&q);
			fprintf(f, "DISPOSE QUEUE: %d\n", r);			
		}
		else
			fprintf(f, "Dequeue: %d\n", dequeue(q));
			

		if(q){
			if(q->size == q->capacity)
				fprintf(f, "Queue is FULL: %d\n", q->size);
			else if(q->size == 0)
				fprintf(f, "Queue is EMPTY: %d\n", q->size);
			else
				fprintf(f, "Queue size = %d\n", q->size);
		}
		
		//printQueueFile(q);
	}

	//makeEmpty(s);

	//disposeQueue(&s);

	/*for(i=0; i<5; i++)
		printf("Top: %d\n", top(s));*/
	
/*	for(i=0; i<20; i++){
		if(!isEmpty(q)){
			printf("Dequeue: %d\n", dequeue(q));
			
			printQueue(q);
		}
		else
			printf("Queue is empty! f=%d, r=%d \n", q->front, q->rear);
	}
*/
			
	return 0;
}

